package org.assistant.common.jdbc.support;

import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.assistant.common.jdbc.core.JdbcTemplate;

public abstract class JdbcUtils {
	protected final static Log log = LogFactory.getLog(JdbcTemplate.class);
	protected final static boolean isDebugEnabled = log.isDebugEnabled();

	/**
	 * Constant that indicates an unknown (or unspecified) SQL type.
	 * 
	 * @see java.sql.Types
	 */
	public static final int TYPE_UNKNOWN = Integer.MIN_VALUE;

	/**
	 * 在ResultSet的元数据中查找指定列序号的列名
	 * 
	 * @param resultSetMetaData
	 * @param columnIndex
	 * @return
	 * @throws SQLException
	 */
	public static String lookupColumnName(ResultSetMetaData resultSetMetaData,
			int columnIndex) throws SQLException {
		String name = resultSetMetaData.getColumnLabel(columnIndex);
		if (name == null || name.length() < 1) {
			name = resultSetMetaData.getColumnName(columnIndex);
		}
		return name;
	}

	/**
	 * 获取ResultSet中指定列序号的值
	 * 
	 * @param rs
	 * @param index
	 * @return
	 * @throws SQLException
	 */
	public static Object getResultSetValue(ResultSet rs, int index)
			throws SQLException {
		Object obj = rs.getObject(index);
		String className = null;
		if (obj != null) {
			className = obj.getClass().getName();
		}
		String metaDataClassName = rs.getMetaData().getColumnClassName(index);

		if (obj instanceof Blob) {
			obj = rs.getBytes(index);
		} else if (obj instanceof Clob) {
			obj = rs.getString(index);
		} else if (className != null
				&& ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ"
						.equals(className))) {
			obj = rs.getTimestamp(index);
		} else if (className != null && className.startsWith("oracle.sql.DATE")) {
			if ("java.sql.Timestamp".equals(metaDataClassName)
					|| "oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
				obj = rs.getTimestamp(index);
			} else {
				obj = rs.getDate(index);
			}
		} else if (obj != null && obj instanceof java.sql.Date) {
			if ("java.sql.Timestamp".equals(metaDataClassName)) {
				obj = rs.getTimestamp(index);
			}
		}
		return obj;
	}

	public static <T> Object getResultSetValue(ResultSet rs, int index,
			Class<T> requiredType) throws SQLException {
		if (requiredType == null) {
			return getResultSetValue(rs, index);
		}

		Object value = null;
		boolean wasNullCheck = false;

		// Explicitly extract typed value, as far as possible.
		if (String.class.equals(requiredType)) {
			value = rs.getString(index);
		} else if (boolean.class.equals(requiredType)
				|| Boolean.class.equals(requiredType)) {
			value = Boolean.valueOf(rs.getBoolean(index));
			wasNullCheck = true;
		} else if (byte.class.equals(requiredType)
				|| Byte.class.equals(requiredType)) {
			value = new Byte(rs.getByte(index));
			wasNullCheck = true;
		} else if (short.class.equals(requiredType)
				|| Short.class.equals(requiredType)) {
			value = new Short(rs.getShort(index));
			wasNullCheck = true;
		} else if (int.class.equals(requiredType)
				|| Integer.class.equals(requiredType)) {
			value = new Integer(rs.getInt(index));
			wasNullCheck = true;
		} else if (long.class.equals(requiredType)
				|| Long.class.equals(requiredType)) {
			value = new Long(rs.getLong(index));
			wasNullCheck = true;
		} else if (float.class.equals(requiredType)
				|| Float.class.equals(requiredType)) {
			value = new Float(rs.getFloat(index));
			wasNullCheck = true;
		} else if (double.class.equals(requiredType)
				|| Double.class.equals(requiredType)
				|| Number.class.equals(requiredType)) {
			value = new Double(rs.getDouble(index));
			wasNullCheck = true;
		} else if (byte[].class.equals(requiredType)) {
			value = rs.getBytes(index);
		} else if (java.sql.Date.class.equals(requiredType)) {
			value = rs.getDate(index);
		} else if (java.sql.Time.class.equals(requiredType)) {
			value = rs.getTime(index);
		} else if (java.sql.Timestamp.class.equals(requiredType)
				|| java.util.Date.class.equals(requiredType)) {
			value = rs.getTimestamp(index);
		} else if (BigDecimal.class.equals(requiredType)) {
			value = rs.getBigDecimal(index);
		} else if (Blob.class.equals(requiredType)) {
			value = rs.getBlob(index);
		} else if (Clob.class.equals(requiredType)) {
			value = rs.getClob(index);
		} else {
			// Some unknown type desired -> rely on getObject.
			value = getResultSetValue(rs, index);
		}

		// Perform was-null check if demanded (for results that the
		// JDBC driver returns as primitives).
		if (wasNullCheck && value != null && rs.wasNull()) {
			value = null;
		}
		return value;
	}

	/**
	 * 根据DatabaseMetaData判断当前数据库是否支持批量提交数据
	 * 
	 * @param con
	 * @return
	 */
	public static boolean supportsBatchUpdates(Connection con) {
		try {
			DatabaseMetaData dbmd = con.getMetaData();
			if (dbmd != null) {
				if (dbmd.supportsBatchUpdates()) {
					log.debug("JDBC driver supports batch updates");
					return true;
				} else {
					log.debug("JDBC driver does not support batch updates");
				}
			}
		} catch (SQLException ex) {
			log
					.debug(
							"JDBC driver 'supportsBatchUpdates' method threw exception",
							ex);
		} catch (AbstractMethodError err) {
			log
					.debug(
							"JDBC driver does not support JDBC 2.0 'supportsBatchUpdates' method",
							err);
		}
		return false;
	}
}
